package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.StatusEvent;
	import flash.events.TimerEvent;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.net.URLVariables;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	import flash.utils.Timer;
	
	import org.flixel.FlxG;
	import org.flixel.FlxSprite;
	import org.flixel.FlxText;
	

	public class Client
	{
		public static const NORMAL_DOMAIN:String = "http://yinnopiano.com/Poofed/";
		public static const FACEBOOK_DOMAIN:String = "http://games.cs.washington.edu/capstone/11sp/elemental/";
		public static const SERVICE_DOMAIN:String = (Elemental.MODE == Elemental.FACEBOOK_MODE) ? FACEBOOK_DOMAIN : NORMAL_DOMAIN;
		
		public static const SUBMIT_PUZZLE:String = "newPuzzle.php";
		public static const GET_PUZZLES_BY_ID:String = "getPlayersPuzzles.php";
		public static const GET_PUZZLES:String = "browsePuzzles.php";
		public static const GET_NUM_PUZZLES:String = "numMaps.php";
		public static const SUBMIT_RATING:String = "rate.php";
		public static const FILTER_FRIENDS:String = "inOurDatabase.php";
		public static const REGISTER_USER:String = "startup.php";
		public static const UPDATE_STAT:String = "updatePlayerStats.php";
		public static const PUZZLE_START:String = "startMap.php";
		public static const PUZZLE_WIN:String = "beatMap.php";
		public static const ISSUE_CHALLENGE:String = "issueChallenge.php";
		
		public function Client() {}
		
		
		/**
		 * Type is either "allMaps" "percentageMaps" or "challengeMaps".
		 * If "allMaps", you must supply a difficulty param.
		 * If "percentageMaps", you must supply a percent param.
		 * If "challengeMaps", you must supply a pid param.
		 * 
		 * Special for facebook
		 */
		public static function loadNumPuzzlesForFB(type:String, difficulty:int, percent:int, playerID:String, callback:Function):void {
			var vars:URLVariables = new URLVariables();
			vars.type = type;
			vars.difficulty = String(difficulty);
			vars.percentage = String(percent);
			vars.pid = playerID;
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + GET_NUM_PUZZLES);
			request.method = URLRequestMethod.GET;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.load(request);
		}
		
		/**
		 * One-method call for grabbing all challenge puzzles for a player id
		 * for facebook
		 */
		public static function loadAllPuzzleChallenges(playerID:String, callback:Function):void {
			loadNumPuzzlesForFB("challengeMaps", 0, 10, playerID, function (e:Event):void {
				loadNPuzzleChallenges(0, int(e.target.data), playerID, callback);
				trace("we loaded " + e.target.data + " challengesmaps");
			});
		}
		
		/**
		 * Returns n puzzle challenges for playerID depending on the params you specified.
		 * for facebook
		 */
		public static function loadNPuzzleChallenges(startNum:int, amount:int, playerID:String, callback:Function):void {
			var vars:URLVariables = new URLVariables();
			vars.type = "challengeMaps";
			vars.start = String(startNum);
			vars.howMany = String(amount);
			vars.pid = playerID;
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + GET_PUZZLES);
			request.method = URLRequestMethod.GET;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.load(request);
		}
		
		/**
		 * Issue a challenge for puzzles
		 * for facebook
		 */
		public static function issueChallenge(theChallenged:String, playerID:String, mapID:String, callback:Function=null):void {
			var vars:URLVariables = new URLVariables();
			vars.theChallenged = theChallenged;
			vars.pid = playerID;
			vars.mid = mapID;
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + ISSUE_CHALLENGE);
			request.method = URLRequestMethod.POST;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, function (e:Event):void {
				trace(e.target.data);
				if (callback != null) {
					callback(e);
				}
			});
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.load(request);
		}
		
		/**
		 * Returns all puzzles created by a certain player.
		 */
		public static function getAllPuzzlesCreatedBy(playerID:String, callback:Function):void {
			var vars:URLVariables = new URLVariables();
			vars.pid = playerID;
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + GET_PUZZLES_BY_ID);
			request.method = URLRequestMethod.GET;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.load(request);
		}
		
		/**
		 * One-method call for grabbing all challenge puzzles for a player id
		 */
		public static function loadAllPuzzlesByDifficultyForFB(difficulty:int, callback:Function):void {
			loadNumPuzzlesForFB("allMaps", difficulty, 10, "", function (e:Event):void {
				loadNPuzzlesByDifficultyForFB(0, int(e.target.data), difficulty, callback);
				trace("we loaded " + e.target.data + " maps for difficulty " + difficulty);
			});
		}
		
		/**
		 * Returns all puzzles created by a certain player.
		 */
		public static function loadNPuzzlesByDifficultyForFB(startNum:int, amount:int, difficulty:int, callback:Function):void {
			var vars:URLVariables = new URLVariables();
			vars.type = "allMaps";
			vars.difficulty = String(difficulty);
			vars.start = String(startNum);
			vars.howMany = String(amount);
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + GET_PUZZLES);
			request.method = URLRequestMethod.GET;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.load(request);
		}
		
		/**
		 * Returns the number of puzzles for this type
		 * for kongregate
		 */
		public static function loadNumPuzzles(type:int, callback:Function):void {
			var vars:URLVariables = new URLVariables();
			vars.difficulty = String(type);
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + GET_NUM_PUZZLES);
			request.method = URLRequestMethod.GET;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.load(request);
		}
		
		/**
		 * Load all the puzzles by a difficulty type
		 * This is the old kongregate call.
		 */
		public static function loadAllPuzzlesByDifficulty(type:int, callback:Function):void {
			loadNumPuzzles(type, function (e:Event):void {
				loadPuzzles(type, 0, int(e.target.data), callback);
			});
		}
		
		/**
		 * Example:
		 * The old kongregate call for puzzleloader
		 */
		public static function loadPuzzles(type:int, startNum:int, amount:int, callback:Function):void {
			var vars:URLVariables = new URLVariables();
			vars.difficulty = String(type);
			vars.start = String(startNum);
			vars.howMany = String(amount);
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + GET_PUZZLES);
			request.method = URLRequestMethod.GET;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.load(request);
		}
		
		/**
		 * Submits a puzzle to the database.
		 * for both kongregate and facebook
		 */
		public static function submitPuzzle(map:String, mapName:String, tileset:int,
											arrowUp:int, arrowDown:int, arrowLeft:int, arrowRight:int, 
											chickens:int, difficulty:int, callback:Function=null):void {
			
			var vars:URLVariables = new URLVariables();
			vars.pid = (Elemental.MODE == Elemental.FACEBOOK_MODE) ? Elemental.fbInfo.userID : Elemental.Log.uid;
			vars.name = mapName;
			vars.contents = map;
			vars.tileset = tileset;
			vars.arrows = arrowUp + "," + arrowDown + "," + arrowLeft + "," + arrowRight;
			vars.chickens = chickens;
			vars.difficulty = difficulty;
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + SUBMIT_PUZZLE);
			request.method = URLRequestMethod.POST;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);

			loader.addEventListener(Event.COMPLETE, function (e:Event):void {
				trace(e.target.data);
				if (callback != null) {
					callback(e);
				}
			});
			
			loader.load(request);
		}
		
		/**
		 * For every URL request, add a listener for IO errors with this
		 * function as the callback.
		 * IO errors can occur when we don't have an internet connection.
		 */
		public static function onIOError(e:IOErrorEvent):void {
			var error:Sprite = new Sprite();
			error.graphics.beginFill(0x000000);
			error.graphics.drawRoundRect(0, 0, 400, 200, 20, 20);
			error.graphics.endFill();
			error.x = (FlxG.width - 400)/2;
			error.y = (FlxG.height - 200)/2;
			
			var tf:TextFormat = new TextFormat();
			tf.font = "Courier New";
			tf.size = 16;
			tf.color = 0xFFFFFF;
			tf.align = TextFormatAlign.CENTER;
			
			var errorText:TextField = new TextField();
			errorText.defaultTextFormat = tf;
			//errorText.text = "IO ERROR:\n" + e.text;
			errorText.text = "Server is unavailable at this time.\nRedirecting you to the menu ...";
			errorText.width = 400;
			errorText.selectable = false;
			errorText.x = error.x;
			errorText.y = error.y + (200 - errorText.textHeight * 1.2)/2;
			
			FlxG.stage.addChild(error);
			FlxG.stage.addChild(errorText);
			
			var timer:Timer = new Timer(4000, 1);
			timer.addEventListener(TimerEvent.TIMER_COMPLETE, function redirect(e:TimerEvent):void {
				timer.stop();
				timer.removeEventListener(TimerEvent.TIMER_COMPLETE, redirect);
				FlxG.stage.removeChild(error);
				FlxG.stage.removeChild(errorText);
				FlxG.switchState(new MenuState());
			});
			timer.start();
		}
		
		/**
		 * Submits a rating to the database
		 * example: http://yinnopiano.com/Poofed/rate.php?id=4&rating=5
		 * (rate.php)
		 */
		public static function submitRating(mapID:int, rating:int, callback:Function=null):void {
			
			var vars:URLVariables = new URLVariables();
			vars.pid = Elemental.Log.uid;
			vars.id = mapID;
			vars.rating = rating;
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + SUBMIT_RATING);
			request.method = URLRequestMethod.POST;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.addEventListener(Event.COMPLETE, function (e:Event):void {
				trace(e.target.data);
				if (callback != null) {
					callback(e);
				}
			});
			
			loader.load(request);
		}
		
		public static function updatePlayerStat(pid:String, cat:String, amount:int, callback:Function=null):void {
			var vars:URLVariables = new URLVariables();
			vars.pid = pid;
			vars.category = cat;
			vars.increment = new String(amount);
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + UPDATE_STAT);
			request.method = URLRequestMethod.POST;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.addEventListener(Event.COMPLETE, function (e:Event):void {
				trace(e.target.data);
				if (callback != null) {
					callback(e);
				}
			});
			
			loader.load(request);
		}
		
		/**
		 * Given a list of friends, filter out all those who are not using the app
		 * (inOurDatabase.php)
		 */
		public static function filterIDs(friends:Array, callback:Function):void {
			var idString:String = "";
			for (var i:int = 0; i < friends.length; i++) {
				var id:String = friends[i]["id"];
				idString += id;
				if (i != friends.length - 1) {
					idString += ":";
				}
			}

			var vars:URLVariables = new URLVariables();
			vars.pids = idString;
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + FILTER_FRIENDS);
			request.method = URLRequestMethod.GET;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.load(request);
		}
		
		/**
		 * Registers user in database if doesn't already exist
		 * Also returns some information.  if you want it!
		 * (startup.php)
		 */
		public static function registerUser(pid:String, callback:Function):void {
			var vars:URLVariables = new URLVariables();
			vars.pid = pid;
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + REGISTER_USER);
			request.method = URLRequestMethod.GET;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, callback);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.load(request);
		}
		
		/**
		 * Records when a puzzle is started
		 * (startMap.php)
		 */
		public static function recordPuzzleStart(playerID:String, mapID:int, callback:Function=null):void {
			var vars:URLVariables = new URLVariables();
			vars.pid = playerID;
			vars.mid = mapID;
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + PUZZLE_START);
			request.method = URLRequestMethod.POST;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, function (e:Event):void {
				trace(e.target.data);
				if (callback != null) {
					callback(e);
				}
			});
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.load(request);
		}
		
		/**
		 * Records when a puzzle is won.
		 * (beatMap.php)
		 */
		public static function recordPuzzleWin(playerID:String, mapID:int, callback:Function=null):void {
			var vars:URLVariables = new URLVariables();
			vars.pid = playerID;
			vars.mid = mapID;
			
			var request:URLRequest = new URLRequest(SERVICE_DOMAIN + PUZZLE_WIN);
			request.method = URLRequestMethod.POST;
			request.data = vars;
			
			var loader:URLLoader = new URLLoader();
			loader.dataFormat = URLLoaderDataFormat.TEXT;
			loader.addEventListener(Event.COMPLETE, function (e:Event):void {
				trace(e.target.data);
				if (callback != null) {
					callback(e);
				}
			});
			loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.load(request);
		}
	}
}